package model.game;

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Rectangle;
import java.util.Iterator;
import java.util.LinkedList;

import model.cell.AbstractCell;
import model.cell.PathCell;
import model.classes.Speed;


/**
 * 
 * 
 * @author alexandre.altun
 */
public class Path {
	
	private LinkedList<AbstractCell> _path;
	
	private Dimension _cellDim;
	
	private Dimension _mapDim;
	
	
	/**
	 * Class constructor.
	 * It takes both the dimension of map and the dimension of a cell as parameter.
	 * 
	 * @param cellDim
	 * @param mapDim
	 */
	public Path(Dimension cellDim, Dimension mapDim) {
		
		_cellDim = cellDim;
		_mapDim = mapDim;
		_path = new LinkedList<AbstractCell>();
		buildPath();
	}
	
	
	/**
	 * Build PathCell collection
	 */
	public void buildPath() {
		
		_path.add(new PathCell(new Point(_cellDim.width*0,_cellDim.width*1), _cellDim));
		_path.add(new PathCell(new Point(_cellDim.width*1,_cellDim.width*1), _cellDim));
		_path.add(new PathCell(new Point(_cellDim.width*2,_cellDim.width*1), _cellDim));
		_path.add(new PathCell(new Point(_cellDim.width*2,_cellDim.width*2), _cellDim));
		_path.add(new PathCell(new Point(_cellDim.width*2,_cellDim.width*3), _cellDim));
		_path.add(new PathCell(new Point(_cellDim.width*2,_cellDim.width*4), _cellDim));
		_path.add(new PathCell(new Point(_cellDim.width*2,_cellDim.width*5), _cellDim));
		_path.add(new PathCell(new Point(_cellDim.width*3,_cellDim.width*5), _cellDim));
		_path.add(new PathCell(new Point(_cellDim.width*4,_cellDim.width*5), _cellDim));
		_path.add(new PathCell(new Point(_cellDim.width*5,_cellDim.width*5), _cellDim));
		_path.add(new PathCell(new Point(_cellDim.width*6,_cellDim.width*5), _cellDim));
		_path.add(new PathCell(new Point(_cellDim.width*7,_cellDim.width*5), _cellDim));
		_path.add(new PathCell(new Point(_cellDim.width*7,_cellDim.width*6), _cellDim));
		_path.add(new PathCell(new Point(_cellDim.width*7,_cellDim.width*7), _cellDim));
		_path.add(new PathCell(new Point(_cellDim.width*7,_cellDim.width*8), _cellDim));
		_path.add(new PathCell(new Point(_cellDim.width*6,_cellDim.width*8), _cellDim));
		_path.add(new PathCell(new Point(_cellDim.width*5,_cellDim.width*8), _cellDim));
		_path.add(new PathCell(new Point(_cellDim.width*4,_cellDim.width*8), _cellDim));
		_path.add(new PathCell(new Point(_cellDim.width*3,_cellDim.width*8), _cellDim));
		_path.add(new PathCell(new Point(_cellDim.width*2,_cellDim.width*8), _cellDim));
		_path.add(new PathCell(new Point(_cellDim.width*1,_cellDim.width*8), _cellDim));
		_path.add(new PathCell(new Point(_cellDim.width*0,_cellDim.width*8), _cellDim));
		_path.size();
		initPath();
	}
	
	
	/**
	 * Set the speed vector of all cells. This speed is used by enemies 
	 * to get their direction on the path
	 */
	public void initPath() {
		
		Iterator<AbstractCell> it = _path.iterator();
		if (!it.hasNext()) return;
		
		PathCell cell = (PathCell) it.next();
		Rectangle cellPosFirst = cell.getRectangle();
		
		if (0 == cellPosFirst.x) {
			cell.speed = new Speed(1, 0);
		} else if (_mapDim.width - 1 == cellPosFirst.x) {
			cell.speed = new Speed(-1, 0);
		} else if (0 == cellPosFirst.y) {
			cell.speed = new Speed(0, 1);
		} else if (_mapDim.height -1 == cellPosFirst.y) {
			cell.speed = new Speed(0, -1);
		}
		
		while ( null != cell ) {
			
			if (it.hasNext()) {
				Rectangle cellPos = cell.getRectangle();
				
				PathCell nextCell = (PathCell) it.next();
				Rectangle nextCellPos = nextCell.getRectangle();
				
				if (nextCellPos.x == cellPos.x) {
					
					if (nextCellPos.y > cellPos.y) {
						nextCell.speed = new Speed(0, 1);
					} else {
						nextCell.speed = new Speed(0, -1);
					}
					
				} else if (nextCellPos.y == cellPos.y) {
					
					if (nextCellPos.x > cellPos.x) {
						nextCell.speed = new Speed(1, 0);
					} else {
						nextCell.speed = new Speed(-1, 0);
					}
					
				} else {
					System.out.println(nextCellPos.y + " ; " + cellPos.y);
				}
				
				cell = nextCell;
				
			} else {
				cell = null;
			}
		}
		return;
	}
	
	
	/**
	 * Draw all path cells on the buffer g
	 * 
	 * @param g
	 */
	public void draw(Graphics g) {

		for (Iterator<AbstractCell> it = _path.iterator(); it.hasNext();) {
			AbstractCell cell = (AbstractCell) it.next();
			cell.draw(g);
		}
	}
	
	
	/**
	 * Return the speed to take to keep going on the path
	 * 
	 * @param x
	 * @param y
	 * @return Speed new speed for current position
	 */
	public Speed getSpeed(float x, float y) {
		
		int gridPosX = (int) (x / _cellDim.width);
		int gridPosY = (int) (y / _cellDim.height);
		
		for (Iterator<AbstractCell> it = _path.iterator(); it.hasNext();) {
			PathCell cell = (PathCell) it.next();
			Rectangle cellPos = cell.getRectangle();
			
			if ( (cellPos.x / cellPos.width) == gridPosX && (cellPos.y / cellPos.height) == gridPosY ) {
				
				int cellSize = _cellDim.width;
				int halfCellSize = (int) (cellSize / 2);
				
				boolean midCellX = cell.speed.speedX != 0 && (int)x % cellSize == halfCellSize;
				boolean midCellY = cell.speed.speedY != 0 && (int)y % cellSize == halfCellSize;
				
				if ( midCellX || midCellY ) {
					//System.out.println("--" +x + " ; " + y+" | "+gridPosX+" ; "+gridPosY + " | "+midCellX+" ; "+midCellY);
					if (it.hasNext()) {
						PathCell nextCell = (PathCell) it.next();
						return (Speed) nextCell.speed.clone();
					} else {
						// We're in last cell
						return (Speed) cell.speed.clone();
					}
				} else {
					//System.out.println(x + " ; " + y+" | "+gridPosX+" ; "+gridPosY);
					return (Speed) cell.speed.clone();
				}
			}
		}
		
		//System.out.println("-- "+x + " ; " + y+" | "+gridPosX+" ; "+gridPosY);
		PathCell firstCell = (PathCell) _path.getFirst();
		return (Speed) firstCell.speed.clone();
	}
	
	
	/**
	 * Is a point visible on the map? 
	 * This method takes in account the size of the enemy as third parameter
	 * in order to compute whether the enemy is visible or not.
	 * 
	 * @param x
	 * @param y
	 * @param enemySize
	 * @return is visible or not 
	 */
	public boolean isOnPath(float x, float y, int enemySize) {
		
		boolean xInRange = x + enemySize > 0 && x - enemySize < _mapDim.width * _cellDim.width;
		boolean yInRange = y + enemySize > 0 && y - enemySize < _mapDim.height * _cellDim.height;
		
		if ( xInRange && yInRange ) {
			return true;
		}
		
		return false;
	}
	
	
	/**
	 * Get the start position of ennemies. It takes a parameter offset
	 * which allows you to shift the position by offset pixels out of the map.
	 * 
	 * @param offset
	 * @return
	 */
	public Point getStartPos(int offset) {
		
		AbstractCell firstCell = _path.getFirst();
		Rectangle rectFirstCell = firstCell.getRectangle();
		
		Point startPos = new Point(rectFirstCell.x, rectFirstCell.y);
		
		if ( 0 == rectFirstCell.x ) {
			startPos.x += -offset;
			startPos.y += (int)(_cellDim.height / 2);
		} else if ( (_mapDim.width - 1) * _cellDim.width == rectFirstCell.x ) {
			startPos.x += _cellDim.width + offset;
			startPos.y += (int)(_cellDim.height / 2);
		
		} else if ( 0 == rectFirstCell.y ) {
			startPos.x += (int)(_cellDim.width / 2);
			startPos.y += -offset;
		} else if ( (_mapDim.height - 1) * _cellDim.height == rectFirstCell.y ) {
			startPos.x += (int)(_cellDim.width / 2);
			startPos.y += _cellDim.height + offset;
		}
		
		return new Point(startPos.x, startPos.y);
	}
	
	
	public LinkedList<AbstractCell> getPath() {
		
		if (_path == null) return null;
		
		return (LinkedList<AbstractCell>) _path.clone();
	}
	
}
